using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityGameFramework.Runtime;

namespace StarForce
{
    /// <summary>
    /// 无限滚动列表脚本
    /// </summary>
    public class LoopCollectionBind : MonoBehaviour , IBeginDragHandler, IEndDragHandler, IDragHandler
    {
        
        
        [SerializeField]private ScrollRect m_ScrollRect = null;

        /// <summary>
        /// 子实体大小
        /// </summary>
        [SerializeField] private Vector2 m_ItemSize = new Vector2(100f, 100f);
        
        /// <summary>
        /// 子实体
        /// </summary>
        [SerializeField]private GameObject m_Temp = null;

        /// <summary>
        /// 无限滚动的方向
        /// </summary>
        [SerializeField] private RectTransform.Axis m_Axis = RectTransform.Axis.Horizontal;

        /// <summary>
        /// 间距
        /// </summary>
        [SerializeField] private float m_Spacing = 0;
        
        /// <summary>
        /// 偏移值
        /// </summary>
        [SerializeField] private RectOffset m_Padding;

        /// <summary>
        /// 多行或者多列
        /// </summary>
        [SerializeField]private int m_Row = 1;
        
        /// <summary>
        /// 数据变化的回调函数
        /// </summary>
        private Action<GameObject, int> m_FuncCallBackFunc;

        private RectTransform m_RectTrans;

//        private float m_PlaneWidth;
//        private float m_PlaneHeight;

        private float m_ContentWidth;
        
        private float m_ContentHeight;

        /// <summary>
        /// 子实体的宽度
        /// </summary>
        private float m_CellObjectWidth;
        
        /// <summary>
        /// 子实体的高度
        /// </summary>
        private float m_CellObjectHeight;

        /// <summary>
        /// ScrollRect content对象
        /// </summary>
        private GameObject m_Content;
        
        /// <summary>
        /// ScrollRect RectTransform对象
        /// </summary>
        private RectTransform m_ContentRectTrans;

        /// <summary>
        /// 是否已经初始化
        /// </summary>
        private bool m_isInited = false;

        /// <summary>
        /// 列表数量
        /// </summary>
        private int m_MaxCount = -1; //列表数量

        /// <summary>
        /// 首位索引
        /// </summary>
        private int m_MinIndex = -1;
        
        /// <summary>
        /// 末尾索引
        /// </summary>
        private int m_MaxIndex = -1;
        
        /// <summary>
        /// 子实体对象池
        /// </summary>
        private Stack<GameObject> m_TempPool = new Stack<GameObject>();
        
        /// <summary>
        /// 存储子实体数据
        /// </summary>
        private TempInfo[] m_TempInfos;
        
        /// <summary>
        /// 是否清空列表
        /// </summary>
        private bool m_IsClearList = false; //是否清空列表

        public bool IsClearList
        {
            get { return m_IsClearList; }
            set { m_IsClearList = value; }
        }

        /// <summary>
        /// 带回调函数的初始化
        /// </summary>
        /// <param name="callBack"></param>
        public void Init(Action<GameObject, int> callBack)
        {
            if (callBack != null)
            {
                m_FuncCallBackFunc = callBack;
            }

            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            if (m_ScrollRect == null)
            {
                Debug.Log("ScrollRect is null");
                return;
            }

            if (m_Temp == null)
            {
                Debug.Log("Temp is null");
                return;
            }
            if (m_isInited)
            {
                //已经初始化直接返回
                return;
            }
            //记录 子实体 信息
            m_CellObjectHeight = m_ItemSize.y; //temp 高度
            m_CellObjectWidth = m_ItemSize.x; // temp 宽度

            //记录panel大小
            m_RectTrans = GetComponent<RectTransform>();
//            m_PlaneHeight = m_RectTrans.rect.height;
//            m_PlaneWidth = m_RectTrans.rect.width;
            
            
            //记录 Content 信息
            m_Content = m_ScrollRect.content.gameObject;
            m_ContentRectTrans = m_Content.GetComponent<RectTransform>();
            Rect contentRect = m_ContentRectTrans.rect;
            m_ContentHeight = contentRect.height;
            m_ContentWidth = contentRect.width;
            
            m_ContentRectTrans.pivot = new Vector2(0f, 1f);
            
            CheckAnchor(m_ContentRectTrans);

            //添加滑动事件              
            m_ScrollRect.onValueChanged.RemoveAllListeners();
            m_ScrollRect.onValueChanged.AddListener(delegate (Vector2 value) { ScrollRectListener(value); });

            m_isInited = true;

        }

        /// <summary>
        /// 展示列表
        /// </summary>
        /// <param name="num"></param>
        public void ShowList(int num)
        {
            m_MinIndex = -1;
            m_MaxIndex = -1;

            //-> 计算 Content 尺寸
            if (m_Axis == RectTransform.Axis.Vertical)
            {
                float contentSize = (m_Spacing + m_CellObjectHeight) * Mathf.CeilToInt((float)num / m_Row); //计算整个content高度 多行
//                float contentSize = (m_Spacing + m_CellObjectHeight) * num; //计算整个content高度 单行
                m_ContentHeight = contentSize;
                m_ContentWidth = m_ContentRectTrans.sizeDelta.x;
                contentSize = contentSize < m_RectTrans.rect.height ? m_RectTrans.rect.height : contentSize;
                m_ContentRectTrans.sizeDelta = new Vector2(m_ContentWidth, contentSize);
                if (num != m_MaxCount)
                {
                    m_ContentRectTrans.anchoredPosition = new Vector2(m_ContentRectTrans.anchoredPosition.x, 0);
                }
            }
            else
            {
                float contentSize = (m_Spacing + m_CellObjectWidth) * Mathf.CeilToInt((float)num / m_Row);
//                float contentSize = (m_Spacing + m_CellObjectWidth) * num;
                m_ContentWidth = contentSize;
                m_ContentHeight = m_ContentRectTrans.sizeDelta.x;
                contentSize = contentSize < m_RectTrans.rect.width ? m_RectTrans.rect.width : contentSize;
                m_ContentRectTrans.sizeDelta = new Vector2(contentSize, m_ContentHeight);
                if (num != m_MaxCount)
                {
                    m_ContentRectTrans.anchoredPosition = new Vector2(0, m_ContentRectTrans.anchoredPosition.y);
                }
            }

            //-> 计算 开始索引
            int lastEndIndex = 0;

           // -> 过多的物体 扔到对象池 ( 首次调 ShowList函数时 则无效 )
            if (m_isInited)
            {
                lastEndIndex = num - m_MaxCount > 0 ? m_MaxCount : num;
                lastEndIndex = m_IsClearList ? 0 : lastEndIndex;

                int count = m_IsClearList ? m_TempInfos.Length : m_MaxCount;
                for (int i = lastEndIndex; i < count; i++)
                {
                    if (m_TempInfos[i].GameObject != null)
                    {
                        SetPoolsObj(m_TempInfos[i].GameObject);
                        m_TempInfos[i].GameObject = null;
                    }
                }
            }
            //计算所有的坐标位置

            TempInfo[] tempCellInfos = m_TempInfos;
            m_TempInfos = new TempInfo[num];
            for (int i = 0; i < num; i++)
            {
                // * -> 存储 已有的数据 ( 首次调 ShowList函数时 则无效 )
                if (m_MaxCount != -1 && i < lastEndIndex)
                {
                    TempInfo tempCellInfo = tempCellInfos[i];
                    //-> 计算是否超出范围
                    float rPos = m_Axis == RectTransform.Axis.Vertical ? tempCellInfo.Pos.y : tempCellInfo.Pos.x;
                    if (!IsOutRange(rPos))
                    {
                        //-> 记录显示范围中的 首位index 和 末尾index
                        m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index
                        m_MaxIndex = i; // 末尾index

                        if (tempCellInfo.GameObject == null)
                        {
                            tempCellInfo.GameObject = GetPoolsObj();
                        }

                        tempCellInfo.GameObject.transform.GetComponent<RectTransform>().anchoredPosition = tempCellInfo.Pos;
                        tempCellInfo.GameObject.name = i.ToString();
                        tempCellInfo.GameObject.SetActive(true);

                        Func(m_FuncCallBackFunc, tempCellInfo.GameObject,i);
                    }
                    else
                    {
                        SetPoolsObj(tempCellInfo.GameObject);  
                        tempCellInfo.GameObject = null;
                    }

                    m_TempInfos[i] = tempCellInfo;
                    continue;
                }

                TempInfo cellInfo = new TempInfo();

                float pos = 0; //坐标( isVertical ? 记录Y : 记录X )
                float rowPos = 0; //计算每排里面的cell 坐标

                // * -> 计算每个Cell坐标
                if(m_Axis == RectTransform.Axis.Vertical)
                {
                    pos =  m_Padding.top+m_CellObjectHeight * Mathf.FloorToInt(i / m_Row) + m_Spacing * Mathf.FloorToInt(i / m_Row)+m_CellObjectHeight/2;
                    rowPos =  m_Padding.left+m_CellObjectWidth/2+m_CellObjectWidth * (i % m_Row) + m_Spacing * (i % m_Row);
                    cellInfo.Pos = new Vector3(rowPos, -pos, 0);
                }
                else
                {
                    pos = m_Padding.left+m_CellObjectWidth * Mathf.FloorToInt(i / m_Row) + m_Spacing * Mathf.FloorToInt(i / m_Row)+m_CellObjectWidth/2;
                    rowPos =m_Padding.top+m_CellObjectWidth/2+ m_CellObjectHeight * (i % m_Row) + m_Spacing * (i % m_Row);
                    cellInfo.Pos = new Vector3(pos, -rowPos, 0);
                }
//                if (m_Axis == RectTransform.Axis.Vertical)
//                {
//                    pos = m_Padding.top+ m_CellObjectHeight * i + m_Spacing * i+m_CellObjectHeight/2;
////                    rowPos = m_CellObjectWidth * i + m_Spacing * i;
//                    rowPos = m_Padding.left+m_CellObjectWidth/2;
//                    cellInfo.Pos = new Vector3(rowPos, -pos, 0);
//                }
//                else
//                {
//                    pos =  m_Padding.left+m_CellObjectWidth * i + m_Spacing *i+m_CellObjectHeight/2;
//                    rowPos =m_Padding.top+ m_CellObjectHeight/2;
//                    cellInfo.Pos = new Vector3(pos, -rowPos, 0);
//                }

                //-> 计算是否超出范围
                float cellPos = m_Axis == RectTransform.Axis.Vertical ? cellInfo.Pos.y : cellInfo.Pos.x;
                if (IsOutRange(cellPos))
                {
                    cellInfo.GameObject = null;
                    m_TempInfos[i] = cellInfo;
                    continue;
                }

                //-> 记录显示范围中的 首位index 和 末尾index
                m_MinIndex = m_MinIndex == -1 ? i : m_MinIndex; //首位index
                m_MaxIndex = i; // 末尾index

                //-> 取或创建 Cell
                GameObject cell = GetPoolsObj();
                cell.transform.GetComponent<RectTransform>().anchoredPosition = cellInfo.Pos;
                cell.gameObject.name = i.ToString();

                //-> 存数据
                cellInfo.GameObject = cell;
                m_TempInfos[i] = cellInfo;

                Func(m_FuncCallBackFunc, cell,i);
            }
            m_MaxCount = num;
            m_isInited = true;
        }

        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="callBack"></param>
        public void SetCallback(Action<GameObject, int> callBack)
        {
            if (callBack != null)
            {
                m_FuncCallBackFunc = callBack;
            }
        }

        /// <summary>
        /// 从对象池中获取实体对象
        /// </summary>
        /// <returns></returns>
        protected virtual GameObject GetPoolsObj()
        {
            GameObject cell = null;
            if (m_TempPool.Count > 0)
            {
                cell = m_TempPool.Pop();
            }

            if (cell == null)
            {
                cell = Instantiate(m_Temp);
            }
            cell.transform.SetParent(m_Content.transform);

            RectTransform cellRect = cell.GetComponent<RectTransform>();

            cellRect.anchorMin = new Vector2(0, 1);
            cellRect.anchorMax = new Vector2(0, 1);
            cellRect.sizeDelta = m_ItemSize;
            cell.transform.localScale = Vector3.one;
            cell.SetActive( true);
            return cell;
        }
        
        /// <summary>
        /// 将无用的实体对象放入对象池
        /// </summary>
        /// <param name="cell"></param>
        protected virtual void SetPoolsObj(GameObject cell)
        {
            if (cell != null)
            {
                m_TempPool.Push(cell);
                cell.SetActive( false);
            }
        }


       /// <summary>
       ///  判断是否超出显示范围
       /// </summary>
       /// <param name="pos"></param>
       /// <returns></returns>
        private bool IsOutRange(float pos)
        {
            Vector3 listP = m_ContentRectTrans.anchoredPosition;
            if(m_Axis == RectTransform.Axis.Vertical)
            {
                if (pos + listP.y > m_CellObjectHeight/2 || pos + listP.y < -m_RectTrans.rect.height-m_CellObjectHeight/2)
                {
                    return true;
                }
            }
            else
            {
                if (pos + listP.x < -m_CellObjectWidth/2 || pos + listP.x > m_RectTrans.rect.width+m_CellObjectWidth/2)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 列表监听
        /// </summary>
        /// <param name="value"></param>
        private void ScrollRectListener(Vector2 value)
        {
            UpdateCheck();
        }

        /// <summary>
        /// 检查是否在显示区域内  更新子实体数据
        /// </summary>
        private void UpdateCheck()
        {
            if (m_TempInfos == null)
            {
                return;
            }
            //检查超出范围
            for (int i = 0, length = m_TempInfos.Length; i < length; i++)
            {
                TempInfo cellInfo = m_TempInfos[i];
                GameObject obj = cellInfo.GameObject;
                Vector3 pos = cellInfo.Pos;

                float rangePos = m_Axis == RectTransform.Axis.Vertical ? pos.y : pos.x;
                //判断是否超出显示范围
                if (IsOutRange(rangePos))
                {
                    //把超出范围的cell 扔进 poolsObj里
                    if (obj != null)
                    {
                        SetPoolsObj(obj);
                        m_TempInfos[i].GameObject = null;
                    }
                }
                else
                {
                    if (obj == null)
                    {
                        //优先从 poolsObj中 取出 （poolsObj为空则返回 实例化的cell）
                        GameObject cell = GetPoolsObj();
                        cell.transform.localPosition = pos;
                        cell.gameObject.name = i.ToString();
                        m_TempInfos[i].GameObject = cell;

                        Func(m_FuncCallBackFunc, cell,i);
                    }
                }
            }
        }
        
        
        /// <summary>
        /// 检查锚点
        /// </summary>
        /// <param name="rectTrans"></param>
        private void CheckAnchor(RectTransform rectTrans)
        {
            if(m_Axis == RectTransform.Axis.Vertical)
            {
                if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) ||
                      (rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(1, 1))))
                {
                    rectTrans.anchorMin = new Vector2(0, 1);
                    rectTrans.anchorMax = new Vector2(1, 1);
                }
            }
            else
            {
                if (!((rectTrans.anchorMin == new Vector2(0, 1) && rectTrans.anchorMax == new Vector2(0, 1)) ||
                      (rectTrans.anchorMin == new Vector2(0, 0) && rectTrans.anchorMax == new Vector2(0, 1))))
                {
                    rectTrans.anchorMin = new Vector2(0, 0);
                    rectTrans.anchorMax = new Vector2(0, 1);
                }
            }
        }
        
        //回调
        private void Func(Action<GameObject, int> func, GameObject selectObject,int index, bool isUpdate = false)
        {
            int num = index;
            if (func != null)
            {
                func(selectObject, num);
            }

        }


        public virtual void OnBeginDrag(PointerEventData eventData)
        {

        }

        public void OnDrag(PointerEventData eventData)
        {
        }

        public virtual void OnEndDrag(PointerEventData eventData)
        {

        }
        
#if UNITY_EDITOR
        protected virtual void OnValidate()
        {
            OnEditorValue();
        }

        protected virtual void Reset()
        {
            OnValidate();
        }
#endif
        
        [System.Diagnostics.Conditional("UNITY_EDITOR")]
        protected virtual void OnEditorValue()
        {
            if (m_ScrollRect == null)
            {
                m_ScrollRect = GetComponentInParent<ScrollRect>();
            }
        }
        
    }

    /// <summary>
    /// 列表每一个子实体的数据类
    /// </summary>
    public class TempInfo
    {
        private GameObject m_GameObject;

        private Vector3 m_Pos;

        public GameObject GameObject
        {
            get { return m_GameObject; }
            set { m_GameObject = value; }
        }

        public Vector3 Pos
        {
            get { return m_Pos; }
            set { m_Pos = value; }
        }
    }
}